package com.bing.client;

import com.bing.common.Message;
import com.bing.common.MessageCodec;
import com.bing.common.MessageType;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

import java.util.Scanner;

/**
 * 聊天客户端
 */
public class ChatClient {

    private final String host;
    private final int port;
    private Channel channel;
    private boolean connected = false;
    private boolean loggedIn = false;
    private String username;

    public ChatClient(String host, int port) {
        this.host = host;
        this.port = port;
    }

    public void setConnected(boolean connected) {
        this.connected = connected;
    }

    public void setLoggedIn(boolean loggedIn) {
        this.loggedIn = loggedIn;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsername() {
        return username;
    }

    /**
     * 启动客户端
     */
    public void start() throws Exception {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            Bootstrap b = new Bootstrap();
            b.group(group)
                    .channel(NioSocketChannel.class)
                    .option(ChannelOption.TCP_NODELAY, true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline().addLast(
                                    // 消息分割
                                    new LengthFieldBasedFrameDecoder(65535, 0, 4, 0, 4),
                                    new LengthFieldPrepender(4),

                                    // 编解码器
                                    new StringDecoder(CharsetUtil.UTF_8),
                                    new StringEncoder(CharsetUtil.UTF_8),
                                    new MessageCodec(),

                                    // 业务处理器
                                    new ClientHandler(ChatClient.this));
                        }
                    });

            // 连接服务器
            ChannelFuture f = b.connect(host, port).sync();
            channel = f.channel();

            System.out.println("连接到服务器: " + host + ":" + port);

            // 启动控制台输入
            handleConsoleInput();

            // 等待连接关闭
            channel.closeFuture().sync();
        } finally {
            group.shutdownGracefully();
        }
    }

    /**
     * 处理控制台输入
     */
    private void handleConsoleInput() {
        Scanner scanner = new Scanner(System.in);
        printHelp();

        while (true) {
            try {
                if (!connected) {
                    System.out.println("未连接到服务器，尝试重新连接...");
                    Thread.sleep(3000);
                    continue;
                }

                System.out.print("> ");
                String input = scanner.nextLine();

                if (input.startsWith("/")) {
                    // 命令处理
                    String[] cmd = input.split("\\s+", 2);
                    String command = cmd[0].substring(1).toLowerCase();

                    switch (command) {
                        case "login":
                            handleLogin(cmd.length > 1 ? cmd[1] : null);
                            break;
                        case "register":
                            handleRegister(cmd.length > 1 ? cmd[1] : null);
                            break;
                        case "logout":
                            handleLogout();
                            break;
                        case "history":
                            handleHistory();
                            break;
                        case "update":
                            handleUpdateInfo(cmd.length > 1 ? cmd[1] : null);
                            break;
                        case "help":
                            printHelp();
                            break;
                        case "exit":
                            if (loggedIn) {
                                handleLogout();
                            }
                            scanner.close();
                            return;
                        default:
                            System.out.println("未知命令，输入 /help 查看帮助");
                            break;
                    }
                } else {
                    // 聊天消息
                    if (loggedIn) {
                        handleChatMessage(input);
                    } else {
                        System.out.println("请先登录，输入 /login 用户名 密码");
                    }
                }
            } catch (Exception e) {
                System.err.println("发生错误: " + e.getMessage());
            }
        }
    }

    /**
     * 处理登录命令
     */
    private void handleLogin(String args) {
        if (loggedIn) {
            System.out.println("您已登录，无需重复登录");
            return;
        }

        if (args == null || !args.contains(" ")) {
            System.out.println("用法: /login 用户名 密码");
            return;
        }

        String[] parts = args.split("\\s+", 2);
        String username = parts[0];
        String password = parts[1];

        System.out.println("正在登录，请稍候...");

        Message message = new Message();
        message.setType(MessageType.LOGIN_REQUEST);
        message.setUsername(username);
        message.setPassword(password);
        message.setSender(username);

        this.username = username;
        channel.writeAndFlush(message);
    }

    /**
     * 处理注册命令
     */
    private void handleRegister(String args) {
        if (args == null || !args.contains(" ")) {
            System.out.println("用法: /register 用户名 密码");
            return;
        }

        String[] parts = args.split("\\s+", 2);
        String username = parts[0];
        String password = parts[1];

        System.out.println("正在注册，请稍候...");

        Message message = new Message();
        message.setType(MessageType.REGISTER_REQUEST);
        message.setUsername(username);
        message.setPassword(password);
        message.setSender(username);

        channel.writeAndFlush(message);
    }

    /**
     * 处理登出命令
     */
    private void handleLogout() {
        if (!loggedIn) {
            System.out.println("您尚未登录");
            return;
        }

        System.out.println("正在登出...");

        Message message = new Message();
        message.setType(MessageType.LOGOUT);
        message.setUsername(username);
        message.setSender(username);

        channel.writeAndFlush(message);
        loggedIn = false;
    }

    /**
     * 处理聊天消息
     */
    private void handleChatMessage(String content) {
        // 检查是否是私聊消息
        if (content.startsWith("@") && content.contains(" ")) {
            String[] parts = content.substring(1).split(" ", 2);
            String receiver = parts[0];
            String message = parts[1];

            // 创建私聊消息
            Message chatMessage = new Message(username, receiver, message);
            channel.writeAndFlush(chatMessage);
        } else {
            // 创建公共消息
            Message chatMessage = new Message(username, content);
            channel.writeAndFlush(chatMessage);
        }
    }

    /**
     * 处理历史消息请求
     */
    private void handleHistory() {
        if (!loggedIn) {
            System.out.println("请先登录");
            return;
        }

        System.out.println("正在获取历史消息...");

        Message message = new Message();
        message.setType(MessageType.HISTORY_REQUEST);
        message.setUsername(username);
        message.setSender(username);

        channel.writeAndFlush(message);
    }

    /**
     * 处理更新用户信息请求
     */
    private void handleUpdateInfo(String args) {
        if (!loggedIn) {
            System.out.println("请先登录");
            return;
        }

        if (args == null) {
            System.out.println("用法: /update 新用户名 新密码 或 /update -u 新用户名 或 /update -p 新密码");
            return;
        }

        String newUsername = null;
        String newPassword = null;

        if (args.startsWith("-u ")) {
            // 只修改用户名
            newUsername = args.substring(3).trim();
            if (newUsername.isEmpty()) {
                System.out.println("新用户名不能为空");
                return;
            }
        } else if (args.startsWith("-p ")) {
            // 只修改密码
            newPassword = args.substring(3).trim();
            if (newPassword.isEmpty()) {
                System.out.println("新密码不能为空");
                return;
            }
        } else {
            // 同时修改用户名和密码
            String[] parts = args.split("\\s+", 2);
            if (parts.length != 2) {
                System.out.println("用法: /update 新用户名 新密码");
                return;
            }
            newUsername = parts[0];
            newPassword = parts[1];
        }

        System.out.println("正在更新用户信息...");

        Message message = new Message();
        message.setType(MessageType.UPDATE_INFO_REQUEST);
        message.setUsername(username);
        message.setSender(username);
        message.setReceiver(newUsername); // 用receiver暂存新用户名
        message.setNewPassword(newPassword);

        channel.writeAndFlush(message);
    }

    /**
     * 打印帮助信息
     */
    private void printHelp() {
        System.out.println("----- 聊天室客户端 -----");
        System.out.println("/login 用户名 密码    - 登录");
        System.out.println("/register 用户名 密码 - 注册");
        System.out.println("/logout              - 登出");
        System.out.println("/history             - 查看历史消息");
        System.out.println("/update 新用户名 新密码 - 更新用户信息");
        System.out.println("/update -u 新用户名   - 只更新用户名");
        System.out.println("/update -p 新密码     - 只更新密码");
        System.out.println("/help                - 显示帮助信息");
        System.out.println("/exit                - 退出");
        System.out.println("直接输入内容发送公共消息");
        System.out.println("@用户名 消息          - 发送私聊消息");
        System.out.println("------------------------");
    }

    public static void main(String[] args) throws Exception {
        String host = "127.0.0.1";
        int port = 9999; // 更新为与服务器相同的端口

        if (args.length >= 2) {
            host = args[0];
            port = Integer.parseInt(args[1]);
        }

        new ChatClient(host, port).start();
    }
}